/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.rw.magallanes.db;

import com.rw.magallanes.core.Category;
import com.rw.magallanes.core.Item;
import com.rw.magallanes.core.Warehouse;
import com.rw.magallanes.utilities.Utilities;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 *
 * @author Trauco
 */
public class Storage {

    public static String STORAGE_DIR = "database";
    public static String STORAGE_FILE = "warehouse.wh";
    //
    private static Storage instance;
    private XStream xstream;
    private int buffer = 2048;
    private Warehouse wh;
    private File file;

    private Storage() {
//        xstream = new XStream(new DomDriver("ISO-8859-1"));
        xstream = new XStream(new DomDriver("UTF-8"));
//        xstream = new XStream(new DomDriver("windows-1252"));
        xstream.setMode(XStream.ID_REFERENCES);

        File storageDir = new File(STORAGE_DIR);
        this.file = new File(storageDir, STORAGE_FILE);

        xstream.processAnnotations(Warehouse.class);
        xstream.processAnnotations(Category.class);
        xstream.processAnnotations(Item.class);
    }

    public static Storage getInstance() {
        instance = (instance == null) ? new Storage() : instance;
        return instance;
    }

    public Warehouse getWarehouse() {
        return this.wh;
    }

    public void save() throws StorageException {
        save(wh, file);
    }

    public void save(Warehouse wh, File file) throws StorageException {
        ZipOutputStream out = null;
        try {
            out = new ZipOutputStream(new FileOutputStream(file));
            out.putNextEntry(new ZipEntry("file.xml"));

            byte data[] = new byte[buffer];
            String fileXml = xstream.toXML(wh);
            InputStream is = new ByteArrayInputStream(fileXml.getBytes());
            int count;
            while ((count = is.read(data, 0, buffer)) != -1) {
                out.write(data, 0, count);
            }
            out.closeEntry();
            is.close();
        } catch (Throwable e) {
            throw new StorageException("Error al guardar fichero: " + file.getAbsolutePath(), e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException ex) {
                    throw new StorageException("Error al guardar fichero: " + file.getAbsolutePath(), ex);
                }
            }
        }
    }

    public void loadDefault() throws StorageException {
        this.wh = new Warehouse();
        save();
    }

    public void load() throws StorageException {
        this.wh = this.open(file);
    }

    public Warehouse open(File file) throws StorageException {
        ZipInputStream zis = null;
        try {
            zis = new ZipInputStream(new FileInputStream(file));
            zis.getNextEntry();

            int count;
            byte data[] = new byte[buffer];
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            while ((count = zis.read(data, 0, buffer)) != -1) {
                os.write(data, 0, count);
            }
            os.flush();
            os.close();

            InputStream is = new ByteArrayInputStream(os.toByteArray());
            return (Warehouse) xstream.fromXML(is);
        } catch (Throwable e) {
            throw new StorageException("Error al abrir fichero: " + file.getAbsolutePath(), e);
        } finally {
            if (zis != null) {
                try {
                    zis.close();
                } catch (IOException ex) {
                    throw new StorageException("Error al abrir fichero: " + file.getAbsolutePath(), ex);
                }
            }
        }

    }

    public static void main(String[] args) {
        write();
//        read();
    }

    private static void write() {
        try {
            Warehouse wh = new Warehouse();
            Category category = new Category("abarrotes");
            Item item1 = new Item("arroz", category);
            Item item2 = new Item("papas", category);

            wh.addCategory(category);
            wh.addItem(category, item1);
            wh.addItem(category, item2);
            Storage.getInstance().save(wh, new File("D:\\test.rar"));
        } catch (StorageException ex) {
            ex.printStackTrace();
        }
    }

    private static void read() {
        try {
            Warehouse wh = Storage.getInstance().open(new File("D:\\test.rar"));
            Utilities.printWarehouse(wh);
        } catch (StorageException ex) {
            Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
